/*
 *
 */
package sentinel;

import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory;
import com.alibaba.csp.sentinel.log.RecordLog;
import com.alibaba.csp.sentinel.transport.CommandCenter;
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;

import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassAnnotationMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import sentinel.command.SimpleHttpCommandCenter;
import sentinel.hearbeat.SimpleHttpHeartbeatSender;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static net.bytebuddy.matcher.ElementMatchers.named;

public class BootInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
    private static final String ENHANCE_CLASS = "org.example.WebApp";
    private static final String INTERCEPT_CLASS = "sentinel.BootInterceptor";
    public static final String ENHANCE_ANNOTATION = "org.springframework.boot.autoconfigure.SpringBootApplication";

    private ScheduledExecutorService pool = pool = new ScheduledThreadPoolExecutor(2,
            new NamedThreadFactory("sentinel-heartbeat-send-cfc-task", true),
            new ThreadPoolExecutor.DiscardOldestPolicy());
    public BootInstrumentation(){
        commandCenterInit();
        heartbeatSenderInit();
    }

    @Override
    protected ClassMatch enhanceClass() {
        //return NameMatch.byName(ENHANCE_CLASS);
        return ClassAnnotationMatch.byClassAnnotationMatch(new String[] {ENHANCE_ANNOTATION});
    }

    @Override
    public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
        return new StaticMethodsInterceptPoint[] {
                new StaticMethodsInterceptPoint() {
                    @Override
                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
                        return named("main");
                    }

                    @Override
                    public String getMethodsInterceptor() {
                        return INTERCEPT_CLASS;
                    }

                    @Override
                    public boolean isOverrideArgs() {
                        return false;
                    }
                }
        };
    }
    //推送客户端心跳
    private void heartbeatSenderInit(){
        HeartbeatSender sender = new SimpleHttpHeartbeatSender();
        pool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    sender.sendHeartbeat();
                } catch (Throwable e) {
                    RecordLog.warn("[myHeartbeatSender] Send heartbeat error", e);
                }
            }
        }, 5000, 10, TimeUnit.MILLISECONDS);
        RecordLog.info("[myHeartbeatSenderInit] HeartbeatSender started: "
                + sender.getClass().getCanonicalName());
    }
    //接收控制台请求
    private void commandCenterInit() {
        try {
            //TODO add by liyi 20200726 SPI获取CommandCenter（SimpleHttpCommandCenter或者NettyHttpCommandCenter）
            CommandCenter commandCenter = new SimpleHttpCommandCenter();
            //TODO add by liyi 20200726 默认为SimpleHttpCommandCenter.
            commandCenter.beforeStart();
            commandCenter.start();
            RecordLog.info("[myCommandCenterInit] Starting command center: "
                    + commandCenter.getClass().getCanonicalName());
        }catch (Exception e){
            RecordLog.warn("[myCommandCenterInitFunc] Exception"+e.getMessage());
        }

    }
}
